<template>
	<view class="page-container">
		<u-navbar :title="navbarTitle" @rightClick="rightClick" border rightText="更新" :autoBack="true"></u-navbar>
		<u-tabs :list="tabList" :scrollable="false" @click="tabClick"></u-tabs>

		<template v-if="tabType === 'index'">
			<view class="BuuetoothServiceList">
				<text>蓝牙服务列表</text>
			</view>
			<scroll-view scroll-y class="box">
				<view class="item" v-for="item in sevicesList" @click="getCharacteristics(item.uuid)">
					<view>
						<text user-select="true">uuid: {{ item.uuid }}</text>
					</view>
					<view>
						<text user-select="true">isPrimary: {{ item.isPrimary }}</text>
					</view>
				</view>
			</scroll-view>
			<view class="BuuetoothServiceList">
				<text>蓝牙特征值列表</text>
			</view>
			<scroll-view scroll-y class="box">
				<view class="item" v-for="item in eigenvalueList" @click="selectEigenvalue(item.uuid)">
					<view>
						<text user-select="true">uuid: {{ item.uuid }}</text>
					</view>
					<view>
						<text v-if="item.properties.read">read，</text>
						<text v-if="item.properties.write">write，</text>
						<text v-if="item.properties.notify">notify，</text>
						<text v-if="item.properties.indicate">indicate，</text>
					</view>
				</view>
			</scroll-view>
			<view class="btnBox">
				<text>已选择的特征值：{{ eigenvalue }}</text>
			</view>
			
			<view class="btnBox">
				 发送字节:<input type="text"
					style="width: 75%;height: 3rem;background-color: rgb(246, 244, 241);margin-left: 5%;border-radius: 20rpx;box-shadow:0 0 8rpx #000;margin-top: 20rpx;"
					placeholder="设置发送字节数" v-model="sendByte" />
				间隔时间:<input type="text"
					style="width: 75%;height: 3rem;background-color: rgb(246, 244, 241);margin-left: 5%;border-radius: 20rpx;box-shadow:0 0 8rpx #000;margin-top: 20rpx;"
					placeholder="设置发送间隔时间" v-model="sendTimes" />
			</view>

			<view class="btnBox">
				<button @click="notify()"
					style="width: 10rem;height: 3rem;margin-top: 1rem;background-color:rgb(138, 145, 159);">③开启消息监听</button>
				<input type="text"
					style="width: 75%;height: 3rem;background-color: rgb(246, 244, 241);margin-left: 5%;border-radius: 20rpx;box-shadow:0 0 8rpx #000;margin-top: 20rpx;"
					placeholder="请填写需要发送的内容" v-model="sendMessage" />
				<view class="clearInput">
					<icon type="clear" @click="clearIptC()"></icon>
				</view>
				<button @click="sendStr()"
					style="width: 10rem;height: 3rem;margin-top: 1rem;background-color:rgb(138, 145, 159);">④发送数据</button>
				<button @click="read()"
					style="width: 10rem;height: 3rem;margin-top: 1rem;background-color:rgb(138, 145, 159);">⑤读取数据</button>
			</view>
			<view class="msg_x" style="background-color: rgb(246, 244, 241);">
				<view class="msg_txt">
					监听到的内容：{{ message }}
				</view>
				<view class="msg_hex">
					监听到的内容（十六进制）：{{ messageHex }}
				</view>
			</view>
		</template>
		<template v-if="tabType === 'output'">
			<view class="text-container">
				<text class="text-title">显示信息</text>
				<view class="text-content">
					<view class="text-content">
						<text>输出电压</text>
						<text>{{ outputInfo.outputVoltage }}V</text>
					</view>
					<view class="text-content">
						<text>输出电流</text>
						<text>{{ outputInfo.outputElectricity }}A</text>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>辅助电压</text>
						<text>{{ outputInfo.auxiliaryVoltage }}V</text>
					</view>
					<view class="text-content"></view>
				</view>
			</view>
			<view class="text-container">
				<text class="text-title">充电桩信息</text>
				<view class="text-content">
					<view class="text-content">
						<text>最小电压</text>
						<text>{{ outputInfo.minVoltage }}V</text>
					</view>
					<view class="text-content">
						<text>最小电流</text>
						<text>{{ outputInfo.minElectricity }}A</text>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>最大电压</text>
						<text>{{ outputInfo.maxVoltage }}V</text>
					</view>
					<view class="text-content">
						<text>最大电流</text>
						<text>{{ outputInfo.maxElectricity }}A</text>
					</view>
				</view>
			</view>
			<view class="text-container">
				<text class="text-title">设置</text>
				<view class="text-content">
					<view class="text-content">
						<text>当前电压</text>
						<text>{{ outputInfo.currentVoltage }}V</text>
					</view>
					<view class="text-content">
						<view class="text-input">
							<u-input border="bottom" style="padding: 0;" v-model="outputInfo.currentVoltage">
								<text slot="suffix">V</text>
							</u-input>
						</view>
						<view class="text-btn">
							<u-button type="primary" text="保存" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>当前电流</text>
						<text>{{ outputInfo.currentElectricity }}A</text>
					</view>
					<view class="text-content">
						<view class="text-input">
							<u-input border="bottom" style="padding: 0;" v-model="outputInfo.currentElectricity">
								<text slot="suffix">A</text>
							</u-input>
						</view>
						<view class="text-btn">
							<u-button type="primary" text="保存" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>接触器</text>
						<text>关闭</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开输出" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>当前状态</text>
						<text>0</text>
					</view>
					<view class="text-content">

					</view>
				</view>
				<view class="text-content">
					<u-button type="primary" text="结束充电" size="small"></u-button>
				</view>
			</view>
		</template>
		<template v-if="tabType === 'settings'">
			<view>
				<view class="text-content">
					<view class="text-content">
						<text>开机输出</text>
						<text>{{ settingsInfo.powerOnOutput ? '开启': '关闭'}}</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>充满自停</text>
						<text>{{ settingsInfo.fullStop ? '开启': '关闭'}}</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开" size="small"></u-button>
						</view>
					</view>
				</view>

				<view class="text-content">
					<view class="text-content">
						<text>关机电流</text>
						<text>{{ settingsInfo.shutdownCurrent }}A</text>
					</view>
					<view class="text-content">
						<view class="text-input">
							<u-input border="bottom" style="padding: 0;" v-model="settingsInfo.shutdownCurrent">
								<text slot="suffix">A</text>
							</u-input>
						</view>
						<view class="text-btn">
							<u-button type="primary" text="保存" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>VIN</text>
						<u-input border="bottom" style="padding: 0;margin: 0 20rpx;"
							v-model="settingsInfo.vin"></u-input>
						<view class="text-btn">
							<u-button type="primary" text="修改" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>屏幕开关</text>
						<text>{{ settingsInfo.screenSwitch ? '开启': '关闭'}}</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<u-button type="primary" text="进入开发者模式" size="small"></u-button>
				</view>
			</view>
		</template>
		<template v-if="tabType === 'safety'">
			<view>
				<view class="text-content">
					<view class="text-content">
						<text>蓝牙名称</text>
						<u-input border="bottom" style="padding: 0;margin: 0 20rpx;" v-model="deviceName"></u-input>
						<view class="text-btn">
							<u-button type="primary" text="修改" size="small"></u-button>
						</view>
					</view>
				</view>
				<view style="padding: 0 20rpx;">
					<u--form labelPosition="top" labelWidth="120" :model="deviceModel" :rules="rules" ref="uForm">
						<u-form-item label="原密码" prop="opassword" borderBottom>
							<u--input v-model="deviceModel.opassword" border="none"></u--input>
						</u-form-item>
						<u-form-item label="新密码" prop="npassword" borderBottom>
							<u--input v-model="deviceModel.npassword" border="none"></u--input>
						</u-form-item>
						<u-form-item label="确认密码" prop="spassword" borderBottom>
							<u--input v-model="deviceModel.spassword" border="none"></u--input>
						</u-form-item>
					</u--form>
				</view>
				<view class="text-content">
					<u-button type="primary" text="修改密码" size="small"></u-button>
				</view>
			</view>
		</template>

		<u-modal :show="showModal" :showConfirmButton="false">
			<view class="slot-content">
				<text>更新中</text>
				<view>
					{{ currentRate }} / {{ totalRate }}
				</view>
				<view>
					失败数量： {{ errorRate }}
				</view>
				<view>
					发送间隔时间： {{ sendTimes }}
				</view>
				<view>
					发送字节： {{ sendByte }}
				</view>
			</view>
		</u-modal>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				tabList: [{
						name: '主页',
						type: 'index'
					},
					{
						name: '输出',
						type: 'output'
					},
					{
						name: '设置',
						type: 'settings'
					},
					{
						name: '安全',
						type: 'safety'
					},
				],
				tabType: 'index',
				outputInfo: {
					outputVoltage: '0.00',
					outputElectricity: '0.00',
					auxiliaryVoltage: '0.00',
					minVoltage: '0.00',
					minElectricity: '0.00',
					maxVoltage: '0.00',
					maxElectricity: '0.00',
					currentVoltage: '0.00',
					currentElectricity: '0.00',
				},
				settingsInfo: {
					powerOnOutput: 0,
					fullStop: 0,
					shutdownCurrent: '0.00',
					vin: '',
					screenSwitch: ''
				},

				navbarTitle: '',
				deviceName: '',
				deviceModel: {
					opassword: '',
					npassword: '',
					spassword: ''
				},
				rules: {
					opassword: {
						type: 'string',
						required: true,
						message: '请填写',
						trigger: ['blur', 'change']
					},
					npassword: {
						type: 'string',
						required: true,
						message: '请填写',
						trigger: ['blur', 'change']
					},
					spassword: {
						type: 'string',
						required: true,
						message: '请填写',
						trigger: ['blur', 'change']
					},
				},

				deviceId: null,
				sevicesList: [],
				serviceUuid: null,
				eigenvalueList: [],
				eigenvalue: null,
				message: "",
				messageHex: "",
				sendMessage: "",
				
				sendTimes: 3000,
				sendByte: 20,

				showModal: false,
				totalRate: 0,
				currentRate: 0,
				errorRate: 0,
			}
		},
		methods: {
			tabClick(item) {
				this.tabType = item.type
			},
			rightClick() {
				uni.showLoading({
					title: '正在下载中'
				})
				uni.request({
					url: 'https://qiniu.kdfff.com/simple_ota.bin',
					responseType: 'arraybuffer',
				}).then(res => {
					this.printbuffs(res.data)
				}).catch(err => {
					console.warn(err)
					uni.hideLoading()
				})
			},
			//连接蓝牙设备
			connect() {
				uni.showToast({
					icon: 'success',
					title: '开始连接'
				})
				let that = this
				uni.createBLEConnection({
					deviceId: this.deviceId,
					success(res) {
						uni.showToast({
							icon: 'success',
							title: '蓝牙连接成功'
						})
						console.log('连接成功')
						setTimeout(() => {
							//获取蓝牙服务
							that.getServices()
						}, 1000)

					},
					fail(err) {
						uni.showToast({
							icon: 'error',
							title: '蓝牙连接失败'
						})
						console.log('连接失败')
						console.log(err)
					}
				})
			},
			//获取蓝牙服务
			getServices() {
				console.log('开始获取蓝牙服务');
				let that = this;
				console.warn(that.deviceId)
				uni.getBLEDeviceServices({
					deviceId: that.deviceId, // 设备ID，在上一步【4】里获取
					success(res) {
						that.sevicesList = res.services
						that.serviceUuid = res.services[0].uuid
						console.log(that.sevicesList, '=================')
					},
					fail(err) {
						console.error(err)
					}
				})
			},
			//获取特征值
			getCharacteristics(uuid) {
				this.serviceUuid = uuid
				let that = this
				uni.getBLEDeviceCharacteristics({
					deviceId: that.deviceId, // 设备ID，在【4】里获取到
					serviceId: that.serviceUuid, // 服务UUID，在【6】里能获取到
					success(res) {
						that.eigenvalueList = res.characteristics
						that.eigenvalue = ''
					},
					fail(err) {
						console.error(err)
					}
				})
			},
			selectEigenvalue(uuid) {
				this.eigenvalue = uuid
			},
			notify() {
				let that = this
				uni.notifyBLECharacteristicValueChange({
					state: true, // 启用 notify 功能
					deviceId: that.deviceId, // 设备ID，在【4】里获取到
					serviceId: that.serviceUuid, // 服务UUID，在【6】里能获取到
					characteristicId: that.eigenvalue, // 特征值，在【7】里能获取到
					success(res) {
						console.log(res)
						uni.showToast({
							icon: 'success',
							title: '开启监听成功'
						})

						// 接受消息的方法
						that.listenValueChange()
					},
					fail(err) {
						console.log(err)
						uni.showToast({
							icon: 'error',
							title: '开启监听失败'
						})
					}
				})
			},
			// ArrayBuffer转16进度字符串示例
			ab2hex(buffer) {
				const hexArr = Array.prototype.map.call(
					new Uint8Array(buffer),
					function(bit) {
						return ('00' + bit.toString(16)).slice(-2)
					}
				)
				return hexArr.join('')
			},
			// 将16进制的内容转成我们看得懂的字符串内容
			hexCharCodeToStr(hexCharCodeStr) {
				var trimedStr = hexCharCodeStr.trim();
				var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
				var len = rawStr.length;
				if (len % 2 !== 0) {
					alert("存在非法字符!");
					return "";
				}
				var curCharCode;
				var resultStr = [];
				for (var i = 0; i < len; i = i + 2) {
					curCharCode = parseInt(rawStr.substr(i, 2), 16);
					resultStr.push(String.fromCharCode(curCharCode));
				}
				return resultStr.join("");
			},
			listenValueChange() {
				let that = this
				uni.onBLECharacteristicValueChange(res => {
					// 结果
					console.log(res, '这是监听成功的回调');
					// 结果里有个value值，该值为 ArrayBuffer 类型，所以在控制台无法用肉眼观察到，必须将该值转换为16进制
					let resHex = that.ab2hex(res.value)
					//console.log(resHex)​;
					that.messageHex = resHex
					// 最后将16进制转换为ascii码，就能看到对应的结果
					let result = that.hexCharCodeToStr(resHex);
					that.message = String(result)
					console.log(String(result), '000000')
				})
			},
			//指令发送分包处理
			async printbuffs(buffer) {
				
				// 1.并行调用多次会存在写失败的可能性
				// 2.建议每次写入不超过20字节
				// 分包处理，延时调用
				let that = this;
				if(!that.sendByte || !that.sendTimes) {
					that.showModal = false
					uni.showModal({
						content: '间隔时间或字节数不能为空',
						showCancel: false
					})
					return
				}
				that.errorRate = 0;
				that.currentRate = 0;
				const offset = that.sendByte; // 偏移量
				this.totalRate = Math.ceil(buffer.byteLength / offset)
				
				uni.hideLoading()
				this.showModal = true
				
				let pos = 0; // 位置
				let bytes = buffer.byteLength; // 总字节
				while (bytes > 0) {
					let endPos = bytes > offset ? (pos + offset) : (pos + bytes);
					const tempBuffer = buffer.slice(pos, endPos);
					pos += offset;
					bytes -= offset;
					if(that.errorRate >= 1) {
						that.showModal = false
						uni.showModal({
							content: '更新失败',
							showCancel: false
						})
						break;
						return
					}
					// 延迟发送
					await that.sendDelay(that.sendTimes, tempBuffer).then(buffer => {
						that.send(buffer)
					})
				}
			},
			// 延时函数
			sendDelay(delay, buffer) {
				return new Promise((resolve, reject) => {
					setTimeout(() => resolve(buffer), delay);
				})
			},
			sendStr() {
				//  向蓝牙设备发送一个0x00的16进制数据
				let msg = this.sendMessage
				console.log(msg, '$$$$$$$$$$$$$$$$$$$$$$$$$$');


				const buffer = new ArrayBuffer(msg.length)
				const dataView = new DataView(buffer)
				dataView.setUint8(0, 0)

				for (var i = 0; i < msg.length; i++) {
					dataView.setUint8(i, msg.charAt(i).charCodeAt())
				}
				this.send(buffer)
			},

			//发送数据
			send(buffer) {
				const that = this
				uni.writeBLECharacteristicValue({
					deviceId: that.deviceId,
					serviceId: that.serviceUuid,
					characteristicId: that.eigenvalue,
					value: buffer,
					success(res) {
						that.currentRate++;
						// uni.showLoading({
						// 	title: `更新中${that.currentRate}/${that.totalRate}`,
						// })
						if (that.currentRate >= that.totalRate) {
							// uni.hideLoading()
							that.showModal = false
							uni.showModal({
								content: '更新成功',
								showCancel: false
							})
						}
						// console.log('writeBLECharacteristicValue success', res.errMsg)
					},
					fail(err) {
						that.errorRate++
						console.log('writeBLECharacteristicValue error', err)
						// that.showModal = false
						// uni.showModal({
						// 	content: '更新失败',
						// 	showCancel: false
						// })
					}
				})
			},
			//读取数据
			read() {
				let that = this
				uni.readBLECharacteristicValue({
					deviceId: that.deviceId,
					serviceId: that.serviceUuid,
					characteristicId: that.eigenvalue,
					success(res) {
						console.log(res, "数据读取成功")
						uni.showToast({
							title: 'read指令发送成功'
						})
					},
					fail(err) {
						console.error(err)
						uni.showToast({
							title: 'read指令发送失败',
							icon: 'error'
						})
					}
				})
			},
			//发送内容的输入框
			clearIptC() {
				this.sendMessage = ""
			}
		},
		onLoad(opt) {
			this.navbarTitle = opt.name;
			this.deviceId = opt.id;
			this.connect()
		}
	}
</script>

<style scoped>
	.page-container {
		padding-top: 128rpx;
	}

	.text-container {
		padding: 10rpx;
	}

	.text-title {
		font-size: 32rpx;
		font-weight: 500;
	}

	.text-input {
		height: 60rpx;
		width: 160rpx;
		line-height: 60rpx;
	}

	.text-content {
		display: flex;
		justify-content: space-between;
		flex: 1;
		padding: 0px 10px;
		line-height: 40px;
	}

	.text-btn {
		padding-top: 10rpx;
	}

	.box {
		width: 100%;
		height: 500rpx;
		box-sizing: border-box;
		margin-bottom: 8rpx;
		border: 1px solid rgb(138, 145, 159);
	}

	.item {
		box-sizing: border-box;
		padding: 10rpx;
		border-bottom: 1px solid gray;
	}

	/* button {
		margin-bottom: 20rpx;
	} */

	.btnBox {
		display: flex;
		display: flex;
		align-items: flex-end;
		flex-wrap: wrap;
	}

	.BuuetoothServiceList {
		width: 100%;
		height: 2rem;
		margin-bottom: 8rpx;
		line-height: 2rem;
		text-align: center;
		font-weight: 700;

	}

	.msg_x {
		border: 2px solid seagreen;
		width: 98%;
		margin: 10rpx auto;
		box-sizing: border-box;
		padding: 20rpx;
	}

	/*	​.msg_txt {
		margin-bottom: 20rpx;
	} */

	.clearInput {
		width: 5%;
		height: 3rem;
		line-height: 3rem;
		float: left;
		margin-left: 2%;
	}
</style>